/*=========================================================================
  UberSim Source Code Release
  -------------------------------------------------------------------------
  Copyright (C) 2002 Manuela Veloso, Brett Browning, Mike Bowling,
  James Bruce; {mmv, brettb, mhb, jbruce}@cs.cmu.edu
  Erick Tryzelaar {erickt}@andrew.cmu.edu
  School of Computer Science, Carnegie Mellon University
  -------------------------------------------------------------------------
  This software is distributed under the GNU General Public License,
  version 2.  If you do not have a copy of this licence, visit
  www.gnu.org, or write: Free Software Foundation, 59 Temple Place,
  Suite 330 Boston, MA 02111-1307 USA.  This program is distributed
  in the hope that it will be useful, but WITHOUT ANY WARRANTY,
  including MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  -------------------------------------------------------------------------*/

#include <ode/ode.h>
#ifdef USE_OPENGL
#include <drawstuff/drawstuff.h>
#endif

#include "../utils/configreader.h"

#include "mmgr.h"

#include "Ball.h"
#include "Event.h"
#include "Geometry.h"
#include "RigidBody.h"
#include "RigidBodyCollider.h"
#include "SphereGeometry.h"
#include "Surface.h"

/*******************************/

// Config data
CR_DECLARE (BALL_MASS);
CR_DECLARE (BALL_RADIUS);
CR_DECLARE (BALL_ROLLING_FRICTION);
CR_DECLARE (BALL_CARPET_FRICTION);
CR_DECLARE (BALL_SLIP_FRICTION);
CR_DECLARE (BALL_ELASTICITY);
CR_DECLARE (BALL_BOUNCE_VEL);

Ball::Ball ()
{
	static bool isConfiged = false;

	if (!isConfiged)
	{
		isConfiged = true;

		CR_SETUP (Ball, BALL_MASS, CR_DOUBLE);
		CR_SETUP (Ball, BALL_RADIUS, CR_DOUBLE);
		CR_SETUP (Ball, BALL_CARPET_FRICTION, CR_DOUBLE);
		CR_SETUP (Ball, BALL_ROLLING_FRICTION, CR_DOUBLE);
		CR_SETUP (Ball, BALL_SLIP_FRICTION, CR_DOUBLE);
		CR_SETUP (Ball, BALL_ELASTICITY, CR_DOUBLE);
		CR_SETUP (Ball, BALL_BOUNCE_VEL, CR_DOUBLE);
	}

	Geometry* ballGeometry = new SphereGeometry (DVAR(BALL_RADIUS), "Ball Geometry");
	ballGeometry->setColor (Vector3 (1.0, 0.5, 0.0));
	model = ballGeometry;

	rigidBody        = new RigidBody ();
	motionController = rigidBody;
	rigidBody->setModel     (ballGeometry);
	rigidBody->setRollingMu (DVAR (BALL_ROLLING_FRICTION));

	dMass mass;
	dMassSetSphere (&mass, 1, DVAR (BALL_RADIUS));
	dMassAdjust    (&mass, DVAR (BALL_MASS));
	dBodySetMass   (rigidBody->getBody (), &mass);

	Surface* ballSurface = new Surface ();
	dSurfaceParameters* sp = &ballSurface->getSurfaceParameters ();
	sp->mode               = dContactBounce | dContactSlip1 | dContactSlip2;// | dContactApprox1;
	sp->mu                 = DVAR (BALL_CARPET_FRICTION);
	sp->bounce             = DVAR (BALL_ELASTICITY);
	sp->bounce_vel         = DVAR (BALL_BOUNCE_VEL);
	sp->slip1              = DVAR (BALL_SLIP_FRICTION);
	sp->slip2              = DVAR (BALL_SLIP_FRICTION);

	RigidBodyCollider* ballCollider = new RigidBodyCollider (rigidBody);
	ballCollider->setSurface             (ballSurface);
	ballGeometry->setCollisionController (ballCollider);
}

/*******************************/

Ball::~Ball ()
{
}

/*******************************/

void Ball::handleEvent (Event* event)
{
	if (!event)
	{
		return;
	}

	VelocityEvent* velocityEvent = dynamic_cast<VelocityEvent *> (event);

	if (velocityEvent)
	{
		//printf ("ball: velocity %f %f %f\n", velocityEvent->linearVelocity.x, velocityEvent->linearVelocity.y, velocityEvent->linearVelocity.z);
		rigidBody->setWorldVelocity (velocityEvent->linearVelocity);

		delete velocityEvent;
		return;
	}

	RigidBodyEntity::handleEvent (event);
}

/*******************************/
